"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Dominando a segmentação de imagens: como as técnicas tradicionais ainda brilham na era digital

Dominando a segmentação de imagens: como as técnicas tradicionais ainda brilham na era digital

Publicado em 2024-11-08
Navegar:276

Introdução

A segmentação de imagens, um dos procedimentos mais básicos em visão computacional, permite que um sistema decomponha e analise várias regiões dentro de uma imagem. Quer você esteja lidando com reconhecimento de objetos, imagens médicas ou direção autônoma, a segmentação é o que divide as imagens em partes significativas.

Embora os modelos de aprendizagem profunda continuem a ser cada vez mais populares nesta tarefa, as técnicas tradicionais de processamento digital de imagens ainda são poderosas e práticas. As abordagens revisadas nesta postagem incluem limiar, detecção de borda, baseada em região e agrupamento, implementando um conjunto de dados bem reconhecido para a análise de imagens de células, o conjunto de dados de imagens MIVIA HEp-2.

Conjunto de dados de imagens MIVIA HEp-2

O conjunto de dados de imagens MIVIA HEp-2 é um conjunto de imagens de células usadas para analisar o padrão de anticorpos antinucleares (ANA) através de células HEp-2. Consiste em fotos 2D tiradas por microscopia de fluorescência. Isso o torna muito adequado para tarefas de segmentação, principalmente aquelas relacionadas à análise de imagens médicas, onde a detecção de regiões celulares é mais importante.

Agora, vamos passar para as técnicas de segmentação usadas para processar essas imagens, comparando seu desempenho com base nas pontuações da F1.


1. Segmentação de limite

Limiar é o processo pelo qual imagens em tons de cinza são convertidas em imagens binárias com base nas intensidades de pixel. No conjunto de dados MIVIA HEp-2, este processo é útil na extração de células do fundo. É simples e eficaz em um nível relativamente grande, especialmente com o método de Otsu, pois ele auto-calcula o limite ideal.

Método de Otsu é um método de limiarização automática, onde tenta encontrar o melhor valor de limiar para produzir a variância intraclasse mínima, separando assim as duas classes: primeiro plano (células) e fundo. O método examina o histograma da imagem e calcula o limite perfeito, onde a soma das variações de intensidade de pixel em cada classe é minimizada.

# Thresholding Segmentation
def thresholding(img):
    # Convert image to grayscale
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # Apply Otsu's thresholding
    _, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY   cv.THRESH_OTSU)

    return thresh

Mastering Image Segmentation: How Traditional Techniques Still Shine in the Digital Age


2. Segmentação de detecção de borda

A detecção de bordas refere-se à identificação de limites de objetos ou regiões, como bordas de células no conjunto de dados MIVIA HEp-2. Dos muitos métodos disponíveis para detectar mudanças abruptas de intensidade, o Canny Edge Detector é o melhor e, portanto, o método mais apropriado para ser usado para detectar limites celulares.

Canny Edge Detector é um algoritmo de vários estágios que pode detectar as bordas detectando áreas de fortes gradientes de intensidade. O processo incorpora suavização com filtro gaussiano, cálculo de gradientes de intensidade, aplicação de supressão não máxima para eliminar respostas espúrias e uma operação final de limiar duplo para a retenção apenas de bordas salientes.

# Segmentação de detecção de borda def edge_detection(img): # Converte imagem em tons de cinza cinza = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # Aplicar desfoque gaussiano cinza = cv.GaussianBlur(cinza, (3, 3), 0) # Calcule os limites inferior e superior para detecção de borda Canny sigma = 0,33 v = np.median(cinza) inferior = int(max(0, (1,0 - sigma) * v)) superior = int(min(255, (1,0 sigma) * v)) # Aplicar detecção de borda Canny bordas = cv.Canny (cinza, inferior, superior) # Dilate as bordas para preencher lacunas kernel = np.ones((5, 5), np.uint8) dilated_edges = cv.dilate(arestas, kernel, iterações=2) # Limpe as bordas usando abertura morfológica bordas_limpas = cv.morphologyEx(dilated_edges, cv.MORPH_OPEN, kernel, iterações = 1) # Encontre componentes conectados e filtre componentes pequenos num_labels, rótulos, estatísticas, _ = cv.connectedComponentsWithStats ( bordas_limpas, conectividade=8 ) tamanho_mín = 500 máscara_filtrada = np.zeros_like(bordas_limpas) para i no intervalo (1, num_labels): if stats[i, cv.CC_STAT_AREA] >= min_size: máscara_filtrada[rótulos == i] = 255 # Encontre os contornos da máscara filtrada contornos, _ = cv.findContours( máscara_filtrada, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE ) # Crie uma máscara preenchida usando os contornos máscara_preenchida = np.zeros_like(cinza) cv.drawContours(filled_mask, contornos, -1, (255), espessura=cv.FILLED) # Realize fechamento morfológico para preencher buracos final_filled_image = cv.morfologiaEx( máscara_preenchida, cv.MORPH_CLOSE, kernel, iterações = 2 ) # Dilate a imagem final preenchida para suavizar as bordas final_filled_image = cv.dilate(final_filled_image, kernel, iterações = 1) retornar imagem_final_filled
# Edge Detection Segmentation
def edge_detection(img):
    # Convert image to grayscale
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # Apply Gaussian blur
    gray = cv.GaussianBlur(gray, (3, 3), 0)

    # Calculate lower and upper thresholds for Canny edge detection
    sigma = 0.33
    v = np.median(gray)
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0   sigma) * v))

    # Apply Canny edge detection
    edges = cv.Canny(gray, lower, upper)

    # Dilate the edges to fill gaps
    kernel = np.ones((5, 5), np.uint8)
    dilated_edges = cv.dilate(edges, kernel, iterations=2)

    # Clean the edges using morphological opening
    cleaned_edges = cv.morphologyEx(dilated_edges, cv.MORPH_OPEN, kernel, iterations=1)

    # Find connected components and filter out small components
    num_labels, labels, stats, _ = cv.connectedComponentsWithStats(
        cleaned_edges, connectivity=8
    )
    min_size = 500
    filtered_mask = np.zeros_like(cleaned_edges)
    for i in range(1, num_labels):
        if stats[i, cv.CC_STAT_AREA] >= min_size:
            filtered_mask[labels == i] = 255

    # Find contours of the filtered mask
    contours, _ = cv.findContours(
        filtered_mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE
    )

    # Create a filled mask using the contours
    filled_mask = np.zeros_like(gray)
    cv.drawContours(filled_mask, contours, -1, (255), thickness=cv.FILLED)

    # Perform morphological closing to fill holes
    final_filled_image = cv.morphologyEx(
        filled_mask, cv.MORPH_CLOSE, kernel, iterations=2
    )

    # Dilate the final filled image to smooth the edges
    final_filled_image = cv.dilate(final_filled_image, kernel, iterations=1)

    return final_filled_image

Mastering Image Segmentation: How Traditional Techniques Still Shine in the Digital Age


3. Segmentação Baseada em Região

A segmentação baseada em região agrupa pixels semelhantes em regiões, dependendo de determinados critérios, como intensidade ou cor. A técnica

Segmentação de bacias hidrográficas pode ser usada para ajudar na segmentação de imagens de células HEp-2 para poder detectar as regiões que representam células; considera as intensidades dos pixels como uma superfície topográfica e delineia regiões distintas.

Segmentação de bacias hidrográficas trata as intensidades dos pixels como uma superfície topográfica. O algoritmo identifica "bacias" nas quais identifica mínimos locais e depois inunda gradualmente essas bacias para ampliar regiões distintas. Esta técnica é bastante útil quando se deseja separar objetos tocantes, como no caso de células em imagens microscópicas, mas pode ser sensível ao ruído. O processo pode ser guiado por marcadores e a segmentação excessiva muitas vezes pode ser reduzida.

# Segmentação baseada em região def região_baseada(img): # Converte imagem em tons de cinza cinza = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # Aplicar limite de Otsu _, limite = cv.threshold(cinza, 0, 255, cv.THRESH_BINARY_INV cv.THRESH_OTSU) # Aplique abertura morfológica para remover ruído kernel = np.ones((3, 3), np.uint8) abertura = cv.morphologyEx (thresh, cv.MORPH_OPEN, kernel, iterações = 2) # Dilate a abertura para obter o fundo sure_bg = cv.dilate(abertura, kernel, iterações=3) # Calcular a transformação de distância dist_transform = cv.distanceTransform(abertura, cv.DIST_L2, 5) # Limite a transformação de distância para obter o primeiro plano _, certeza_fg = cv.threshold(dist_transform, 0,2 * dist_transform.max(), 255, 0) claro_fg = np.uint8(certo_fg) # Encontre a região desconhecida desconhecido = cv.subtract(sure_bg, sure_fg) # Rotule os marcadores para o algoritmo da bacia hidrográfica _, marcadores = cv.connectedComponents(sure_fg) marcadores = marcadores 1 marcadores[desconhecido == 255] = 0 # Aplicar algoritmo de bacia hidrográfica marcadores = cv.watershed(img, marcadores) # Cria uma máscara para a região segmentada máscara = np.zeros_like(cinza, dtype=np.uint8) máscara[marcadores == 1] = 255 máscara de retorno
# Edge Detection Segmentation
def edge_detection(img):
    # Convert image to grayscale
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # Apply Gaussian blur
    gray = cv.GaussianBlur(gray, (3, 3), 0)

    # Calculate lower and upper thresholds for Canny edge detection
    sigma = 0.33
    v = np.median(gray)
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0   sigma) * v))

    # Apply Canny edge detection
    edges = cv.Canny(gray, lower, upper)

    # Dilate the edges to fill gaps
    kernel = np.ones((5, 5), np.uint8)
    dilated_edges = cv.dilate(edges, kernel, iterations=2)

    # Clean the edges using morphological opening
    cleaned_edges = cv.morphologyEx(dilated_edges, cv.MORPH_OPEN, kernel, iterations=1)

    # Find connected components and filter out small components
    num_labels, labels, stats, _ = cv.connectedComponentsWithStats(
        cleaned_edges, connectivity=8
    )
    min_size = 500
    filtered_mask = np.zeros_like(cleaned_edges)
    for i in range(1, num_labels):
        if stats[i, cv.CC_STAT_AREA] >= min_size:
            filtered_mask[labels == i] = 255

    # Find contours of the filtered mask
    contours, _ = cv.findContours(
        filtered_mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE
    )

    # Create a filled mask using the contours
    filled_mask = np.zeros_like(gray)
    cv.drawContours(filled_mask, contours, -1, (255), thickness=cv.FILLED)

    # Perform morphological closing to fill holes
    final_filled_image = cv.morphologyEx(
        filled_mask, cv.MORPH_CLOSE, kernel, iterations=2
    )

    # Dilate the final filled image to smooth the edges
    final_filled_image = cv.dilate(final_filled_image, kernel, iterations=1)

    return final_filled_image

Mastering Image Segmentation: How Traditional Techniques Still Shine in the Digital Age


4. Segmentação baseada em cluster

Técnicas de agrupamento como

K-Means tendem a agrupar os pixels em clusters semelhantes, o que funciona bem quando se deseja segmentar células em ambientes multicoloridos ou complexos, como visto em imagens de células HEp-2. Fundamentalmente, isso poderia representar diferentes classes, como uma região celular versus um plano de fundo.

K-means é um algoritmo de aprendizado não supervisionado para agrupar imagens com base na similaridade de pixel de cor ou intensidade. O algoritmo seleciona aleatoriamente K centróides, atribui cada pixel ao centróide mais próximo e atualiza o centróide iterativamente até convergir. É particularmente eficaz na segmentação de uma imagem que possui múltiplas regiões de interesse muito diferentes umas das outras.

# Segmentação de cluster agrupamento def (img): # Converte imagem em tons de cinza cinza = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # Remodelar a imagem Z = cinza.reshape((-1, 3)) Z = np.float32(Z) # Defina os critérios para agrupamento k-means critérios = (cv.TERM_CRITERIA_EPS cv.TERM_CRITERIA_MAX_ITER, 10, 1,0) # Defina o número de clusters K = 2 # Executar agrupamento k-means _, rótulo, centro = cv.kmeans(Z, K, Nenhum, critérios, 10, cv.KMEANS_RANDOM_CENTERS) # Converte os valores centrais para uint8 centro = np.uint8(centro) # Remodele o resultado res = centro[label.flatten()] res = res.reshape((gray.shape)) #Aplica limite ao resultado _, res = cv.threshold(res, 0, 255, cv.THRESH_BINARY cv.THRESH_OTSU) retornar res
# Edge Detection Segmentation
def edge_detection(img):
    # Convert image to grayscale
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # Apply Gaussian blur
    gray = cv.GaussianBlur(gray, (3, 3), 0)

    # Calculate lower and upper thresholds for Canny edge detection
    sigma = 0.33
    v = np.median(gray)
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0   sigma) * v))

    # Apply Canny edge detection
    edges = cv.Canny(gray, lower, upper)

    # Dilate the edges to fill gaps
    kernel = np.ones((5, 5), np.uint8)
    dilated_edges = cv.dilate(edges, kernel, iterations=2)

    # Clean the edges using morphological opening
    cleaned_edges = cv.morphologyEx(dilated_edges, cv.MORPH_OPEN, kernel, iterations=1)

    # Find connected components and filter out small components
    num_labels, labels, stats, _ = cv.connectedComponentsWithStats(
        cleaned_edges, connectivity=8
    )
    min_size = 500
    filtered_mask = np.zeros_like(cleaned_edges)
    for i in range(1, num_labels):
        if stats[i, cv.CC_STAT_AREA] >= min_size:
            filtered_mask[labels == i] = 255

    # Find contours of the filtered mask
    contours, _ = cv.findContours(
        filtered_mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE
    )

    # Create a filled mask using the contours
    filled_mask = np.zeros_like(gray)
    cv.drawContours(filled_mask, contours, -1, (255), thickness=cv.FILLED)

    # Perform morphological closing to fill holes
    final_filled_image = cv.morphologyEx(
        filled_mask, cv.MORPH_CLOSE, kernel, iterations=2
    )

    # Dilate the final filled image to smooth the edges
    final_filled_image = cv.dilate(final_filled_image, kernel, iterations=1)

    return final_filled_image

Mastering Image Segmentation: How Traditional Techniques Still Shine in the Digital Age


Avaliando as técnicas usando pontuações F1

A

pontuação F1 é uma medida que combina precisão e recall para comparar a imagem de segmentação prevista com a imagem real. É a média harmônica de precisão e recuperação, útil em casos de alto desequilíbrio de dados, como em conjuntos de dados de imagens médicas.

Calculamos a pontuação F1 para cada método de segmentação nivelando a verdade básica e a imagem segmentada e calculando a pontuação F1 ponderada.


def calcula_f1_score(imagem_de_solo, imagem_segmentada): imagem_do_chão = imagem_do_chão.flatten() imagem_segmentada = imagem_segmentada.flatten() retornar f1_score(imagem_ground, imagem_segmentada, média="ponderada")
# Edge Detection Segmentation
def edge_detection(img):
    # Convert image to grayscale
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # Apply Gaussian blur
    gray = cv.GaussianBlur(gray, (3, 3), 0)

    # Calculate lower and upper thresholds for Canny edge detection
    sigma = 0.33
    v = np.median(gray)
    lower = int(max(0, (1.0 - sigma) * v))
    upper = int(min(255, (1.0   sigma) * v))

    # Apply Canny edge detection
    edges = cv.Canny(gray, lower, upper)

    # Dilate the edges to fill gaps
    kernel = np.ones((5, 5), np.uint8)
    dilated_edges = cv.dilate(edges, kernel, iterations=2)

    # Clean the edges using morphological opening
    cleaned_edges = cv.morphologyEx(dilated_edges, cv.MORPH_OPEN, kernel, iterations=1)

    # Find connected components and filter out small components
    num_labels, labels, stats, _ = cv.connectedComponentsWithStats(
        cleaned_edges, connectivity=8
    )
    min_size = 500
    filtered_mask = np.zeros_like(cleaned_edges)
    for i in range(1, num_labels):
        if stats[i, cv.CC_STAT_AREA] >= min_size:
            filtered_mask[labels == i] = 255

    # Find contours of the filtered mask
    contours, _ = cv.findContours(
        filtered_mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE
    )

    # Create a filled mask using the contours
    filled_mask = np.zeros_like(gray)
    cv.drawContours(filled_mask, contours, -1, (255), thickness=cv.FILLED)

    # Perform morphological closing to fill holes
    final_filled_image = cv.morphologyEx(
        filled_mask, cv.MORPH_CLOSE, kernel, iterations=2
    )

    # Dilate the final filled image to smooth the edges
    final_filled_image = cv.dilate(final_filled_image, kernel, iterations=1)

    return final_filled_image
Em seguida, visualizamos as pontuações F1 de diferentes métodos usando um gráfico de barras simples:

Mastering Image Segmentation: How Traditional Techniques Still Shine in the Digital Age


Conclusão

Embora muitas abordagens recentes para segmentação de imagens estejam surgindo, técnicas tradicionais de segmentação, como limiar, detecção de bordas, métodos baseados em região e agrupamento, podem ser muito úteis quando aplicadas a conjuntos de dados como o conjunto de dados de imagens MIVIA HEp-2.

Cada método tem sua força:

  • Limiar é bom para segmentação binária simples.
  • Edge Detection é uma técnica ideal para a detecção de limites.
  • A segmentação
  • baseada em região é muito útil para separar componentes conectados de seus vizinhos.
  • Os métodos de
  • Clustering são adequados para tarefas de segmentação multirregional.
Ao avaliar esses métodos usando pontuações F1, entendemos as vantagens e desvantagens que cada um desses modelos tem. Esses métodos podem não ser tão sofisticados quanto os desenvolvidos nos modelos mais recentes de aprendizagem profunda, mas ainda são rápidos, interpretáveis ​​e utilizáveis ​​em uma ampla gama de aplicações.


Obrigado pela leitura! Espero que esta exploração das técnicas tradicionais de segmentação de imagens inspire seu próximo projeto. Sinta-se à vontade para compartilhar suas idéias e experiências nos comentários abaixo!

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/ahmedmbutt/mastering-image-segmentation-how-traditional-techniques-still-shine-in-the-digital-age-36fa?1 Se houver alguma violação, por favor entre em contato com study_golang@163 .comdelete
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3